using System;
using System.Collections.Generic;
using System.Windows.Forms;
using OhioState.AssetManaged;
using OhioState.Math;

namespace OhioState.Controls
{
    //
    // Matrix Control - encapsulates a set of numeric up downs to provide a single control that
    //  represents a matrix.  This control can be set to modify matrices of size 2x2, 3x3 and 4x4.
    //  NumericUpDown decimal places, increment steps, and min and max values can all be easily set
    //  by the user.  This control will autosize to ensure every value is visible while taking up the
    //  least possible space.
    //
    public partial class MatrixControl : UserControl
    {
        //
        // Properties of numericUpDowns - matrix size, decimal places, increment and max value
        //  List of the numeric up downs for each matrix size
        //
        private int matrixSize;
        private int decimalPlaces;
        private float increment;
        private float max;
        private List<System.Windows.Forms.NumericUpDown> numericUpDowns;
        private List<System.Windows.Forms.NumericUpDown> size3;
        private List<System.Windows.Forms.NumericUpDown> size4;

        //
        // Event for Matrix Control which informs subscribers that the control has changed
        //
        public event System.EventHandler ValueChanged;
        //
        // Event helper for firing events
        //
        protected EventsStrategyAbstract _eventsHelper;

        //
        // Constructor - set up all the possible numericUpDowns that we may be using
        //
        public MatrixControl()
        {
            InitializeComponent();

            matrixSize = 2; // 2x2
            decimalPlaces = 5;
            increment = 0.01f;
            max = 1000000f;

            numericUpDowns = new List<System.Windows.Forms.NumericUpDown>();
            size3 = new List<System.Windows.Forms.NumericUpDown>();
            size4 = new List<System.Windows.Forms.NumericUpDown>();

            //
            // Add all updowns to list
            //
            size3.Add(this.numericUpDown13);
            size3.Add(this.numericUpDown23);
            size3.Add(this.numericUpDown31);
            size3.Add(this.numericUpDown32);
            size3.Add(this.numericUpDown33);

            size4.Add(this.numericUpDown14);
            size4.Add(this.numericUpDown24);
            size4.Add(this.numericUpDown34);
            size4.Add(this.numericUpDown41);
            size4.Add(this.numericUpDown42);
            size4.Add(this.numericUpDown43);
            size4.Add(this.numericUpDown44);

            numericUpDowns.Add(this.numericUpDown11);
            numericUpDowns.Add(this.numericUpDown12);
            numericUpDowns.Add(this.numericUpDown21);
            numericUpDowns.Add(this.numericUpDown22);
            numericUpDowns.Add(this.numericUpDown13);
            numericUpDowns.Add(this.numericUpDown23);
            numericUpDowns.Add(this.numericUpDown31);
            numericUpDowns.Add(this.numericUpDown32);
            numericUpDowns.Add(this.numericUpDown33);
            numericUpDowns.Add(this.numericUpDown14);
            numericUpDowns.Add(this.numericUpDown24);
            numericUpDowns.Add(this.numericUpDown34);
            numericUpDowns.Add(this.numericUpDown41);
            numericUpDowns.Add(this.numericUpDown42);
            numericUpDowns.Add(this.numericUpDown43);
            numericUpDowns.Add(this.numericUpDown44);

            _eventsHelper = new EventsStrategyAsync();
        }

        //
        // Public properties - set basic numericUpDown properties
        //
        public int DecimalPlaces
        {
            get { return decimalPlaces; }
            set
            {
                decimalPlaces = value;

                this.tableLayoutPanel1.SuspendLayout();
                this.SuspendLayout();

                foreach (System.Windows.Forms.NumericUpDown n in numericUpDowns)
                {
                    n.DecimalPlaces = decimalPlaces;
                }

                this.tableLayoutPanel1.ResumeLayout(false);
                this.tableLayoutPanel1.PerformLayout();
                this.ResumeLayout(false);
                this.PerformLayout();
            }
        }

        public float Increment
        {
            get { return increment; }
            set
            {
                increment = value;

                this.tableLayoutPanel1.SuspendLayout();
                this.SuspendLayout();

                foreach (System.Windows.Forms.NumericUpDown n in numericUpDowns)
                {
                    n.Increment = new Decimal(increment);
                }

                this.tableLayoutPanel1.ResumeLayout(false);
                this.tableLayoutPanel1.PerformLayout();
                this.ResumeLayout(false);
                this.PerformLayout();
            }
        }

        public float Max
        {
            get { return max; }
            set
            {
                max = value;

                this.tableLayoutPanel1.SuspendLayout();
                this.SuspendLayout();

                foreach (System.Windows.Forms.NumericUpDown n in numericUpDowns)
                {
                    n.Maximum = new Decimal(max);
                    n.Minimum = new Decimal(-max);
                }

                this.tableLayoutPanel1.ResumeLayout(false);
                this.tableLayoutPanel1.PerformLayout();
                this.ResumeLayout(false);
                this.PerformLayout();
            }
        }

        //
        // Set the size of the matrix, set the visibility of the appropriate number of cells
        //
        public int MatrixSize
        {
            get { return matrixSize; }
            set
            {
                if ((value >= 2) && (value <= 4))
                {
                    matrixSize = value;

                    this.tableLayoutPanel1.SuspendLayout();
                    this.SuspendLayout();

                    if (matrixSize < 3)
                    {
                        foreach (System.Windows.Forms.NumericUpDown n in size3)
                        {
                            n.Visible = false;
                        }
                    }
                    else
                    {
                        foreach (System.Windows.Forms.NumericUpDown n in size3)
                        {
                            n.Visible = true;
                        }
                    }
                    if (matrixSize < 4)
                    {
                        foreach (System.Windows.Forms.NumericUpDown n in size4)
                        {
                            n.Visible = false;
                        }
                    }
                    else
                    {
                        foreach (System.Windows.Forms.NumericUpDown n in size4)
                        {
                            n.Visible = true;
                        }
                    }
                    
                    this.tableLayoutPanel1.ResumeLayout(false);
                    this.tableLayoutPanel1.PerformLayout();
                    this.ResumeLayout(false);
                    this.PerformLayout();
                }
            }
        }

        #region Matrix Accessors
        //
        // Accessors to get and set data in the matrix
        //  The accessor will return the type of matrix that it is currently set upt to modify.
        //  So depending on the settings of MatrixSize, this can return 1 of 3 different 
        //  matrix types.  The set will automatically reset the values of these properties if the
        //  set routine is given a type of matrix different than what the control is currently modifying.
        //
        public Matrix Value
        {
            get
            {
                Matrix mat = null;
                if (matrixSize == 2)
                {
                    Matrix2 m = new Matrix2();
                    m[0, 0] = Decimal.ToSingle(numericUpDown11.Value);
                    m[0, 1] = Decimal.ToSingle(numericUpDown12.Value);
                    m[1, 0] = Decimal.ToSingle(numericUpDown21.Value);
                    m[1, 1] = Decimal.ToSingle(numericUpDown22.Value);
                    mat = m;
                }
                else if (matrixSize == 3)
                {
                    Matrix3 m = new Matrix3();
                    m[0, 0] = Decimal.ToSingle(numericUpDown11.Value);
                    m[0, 1] = Decimal.ToSingle(numericUpDown12.Value);
                    m[1, 0] = Decimal.ToSingle(numericUpDown21.Value);
                    m[1, 1] = Decimal.ToSingle(numericUpDown22.Value);

                    m[0, 2] = Decimal.ToSingle(numericUpDown13.Value);
                    m[1, 2] = Decimal.ToSingle(numericUpDown23.Value);
                    m[2, 0] = Decimal.ToSingle(numericUpDown31.Value);
                    m[2, 1] = Decimal.ToSingle(numericUpDown32.Value);
                    m[2, 2] = Decimal.ToSingle(numericUpDown33.Value);

                    mat = m;
                }
                else if (matrixSize == 4)
                {
                    Matrix4 m = new Matrix4();
                    m[0, 0] = Decimal.ToSingle(numericUpDown11.Value);
                    m[0, 1] = Decimal.ToSingle(numericUpDown12.Value);
                    m[1, 0] = Decimal.ToSingle(numericUpDown21.Value);
                    m[1, 1] = Decimal.ToSingle(numericUpDown22.Value);

                    m[0, 2] = Decimal.ToSingle(numericUpDown13.Value);
                    m[1, 2] = Decimal.ToSingle(numericUpDown23.Value);
                    m[2, 0] = Decimal.ToSingle(numericUpDown31.Value);
                    m[2, 1] = Decimal.ToSingle(numericUpDown32.Value);
                    m[2, 2] = Decimal.ToSingle(numericUpDown33.Value);

                    m[0, 3] = Decimal.ToSingle(numericUpDown14.Value);
                    m[1, 3] = Decimal.ToSingle(numericUpDown24.Value);
                    m[2, 3] = Decimal.ToSingle(numericUpDown34.Value);
                    m[3, 0] = Decimal.ToSingle(numericUpDown41.Value);
                    m[3, 1] = Decimal.ToSingle(numericUpDown42.Value);
                    m[3, 2] = Decimal.ToSingle(numericUpDown43.Value);
                    m[3, 3] = Decimal.ToSingle(numericUpDown44.Value);
                    
                    mat = m;
                }

                return mat;
            }
            set
            {
                if (value is Matrix2)
                {
                    MatrixSize = 2;
                    Matrix2 mat = (Matrix2)value;
                    numericUpDown11.Value = new Decimal(mat[0, 0]);
                    numericUpDown12.Value = new Decimal(mat[0, 1]);
                    numericUpDown21.Value = new Decimal(mat[1, 0]);
                    numericUpDown22.Value = new Decimal(mat[1, 1]);
                }
                else if (value is Matrix3)
                {
                    MatrixSize = 3;
                    Matrix3 mat = (Matrix3)value;
                    numericUpDown11.Value = new Decimal(mat[0, 0]);
                    numericUpDown12.Value = new Decimal(mat[0, 1]);
                    numericUpDown21.Value = new Decimal(mat[1, 0]);
                    numericUpDown22.Value = new Decimal(mat[1, 1]);

                    numericUpDown13.Value = new Decimal(mat[0, 2]);
                    numericUpDown23.Value = new Decimal(mat[1, 2]);
                    numericUpDown31.Value = new Decimal(mat[2, 0]);
                    numericUpDown32.Value = new Decimal(mat[2, 1]);
                    numericUpDown33.Value = new Decimal(mat[2, 2]);
                }
                else if (value is Matrix4)
                {
                    MatrixSize = 4;
                    Matrix4 mat = (Matrix4)value;
                    numericUpDown11.Value = new Decimal(mat[0, 0]);
                    numericUpDown12.Value = new Decimal(mat[0, 1]);
                    numericUpDown21.Value = new Decimal(mat[1, 0]);
                    numericUpDown22.Value = new Decimal(mat[1, 1]);

                    numericUpDown13.Value = new Decimal(mat[0, 2]);
                    numericUpDown23.Value = new Decimal(mat[1, 2]);
                    numericUpDown31.Value = new Decimal(mat[2, 0]);
                    numericUpDown32.Value = new Decimal(mat[2, 1]);
                    numericUpDown33.Value = new Decimal(mat[2, 2]);

                    numericUpDown14.Value = new Decimal(mat[0, 3]);
                    numericUpDown24.Value = new Decimal(mat[1, 3]);
                    numericUpDown34.Value = new Decimal(mat[2, 3]);
                    numericUpDown41.Value = new Decimal(mat[3, 0]);
                    numericUpDown42.Value = new Decimal(mat[3, 1]);
                    numericUpDown43.Value = new Decimal(mat[3, 2]);
                    numericUpDown44.Value = new Decimal(mat[3, 3]);
                }
            }
        }
        #endregion


        private void control_ValueChanged(object sender, EventArgs e)
        {
            _eventsHelper.Fire(ValueChanged, this, e);
        }

    }
}
